﻿using Common.Exception;
using DataStructCenter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AlgorithmCenter
{
    /// <summary>
    /// 基于LRU算法的缓存机制
    /// 实现数据结构：双向链表+字典
    /// </summary>
    public class CacheLRUEngine<K,V> 
    {
        //双向链表，维护key是否被使用
        private DoublyLinkedList<K> _keyLruQue = new DoublyLinkedList<K>();
        //数据存储字典
        private Dictionary<K, V> _cacheMemory = new Dictionary<K, V>();
        //key和链表节点的字典
        private Dictionary<K, DoublyNode<K>> _keyToNodeMap = new Dictionary<K, DoublyNode<K>>();

        //缓存容量
        private Int32 _capacity = 100000;
        //缓存大小
        private Int32 _size = 0;

        public Int32 Capacity
        {
            get
            {
                return _capacity;
            }
            set
            {
                if (value <= 0)
                    throw new NonpositiveException("缓存容量必须大于零");
                _capacity = value;
            }
        }

        public Int32 Size
        {
            get {
                return _size;
            }
            
        }

        public bool Set(K key,V value)
        {
            try
            {
                if (_cacheMemory.ContainsKey(key))
                {
                    _cacheMemory.Remove(key);
                    _cacheMemory.Add(key, value);
                }
                else
                {
                    if (_capacity - _size <= 0)
                    {
                        //删除最近最少使用的缓存
                        DelLRUCache();
                        _size--;
                    }
                    _cacheMemory.Add(key, value);
                    _keyToNodeMap.Add(key, _keyLruQue.Push(key));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
            _size++;
            return true;
            
        }

        public V Get(K key)
        {
            if (_cacheMemory.ContainsKey(key))
            {
                //从key-node映射字典中获取到key对应的节点
                _keyToNodeMap.TryGetValue(key, out DoublyNode<K> node);

                //从LRU队列中删除key对应的节点
                node.PrePoint.NextPoint = node.NextPoint;
                node.NextPoint.PrePoint = node.PrePoint;
                node = null;

                //将key加入到LRU队列头部
                DoublyNode<K> addr = _keyLruQue.Push(key);

                //跟新映射
                _keyToNodeMap.Remove(key);
                _keyToNodeMap.Add(key, addr);


                //返回取到的值
                bool res = _cacheMemory.TryGetValue(key, out V value);
                return res ? value : default(V);
            }
            else
            {
                throw new NonCacheException("key不存在");
            }
           
        }

        private bool DelLRUCache()
        {
            K tempKey = _keyLruQue.Tail.Value;
            _keyLruQue.DelFromTail();
            _keyToNodeMap.Remove(tempKey);
            _cacheMemory.Remove(tempKey);
            return true;
        }

        //删除缓存
        public bool DelCacheByKey(K key)
        {
            if (!_cacheMemory.ContainsKey(key))
                return true;
            _keyToNodeMap.TryGetValue(key,out DoublyNode<K> node);
            _keyLruQue.DelNode(node);
            _keyToNodeMap.Remove(key);
            _cacheMemory.Remove(key);
            return true;
        }

        //缓存 控制台可视化
        public void VisualizationCache()
        {
            Console.Write("Cache: ");
            _cacheMemory.ToList().ForEach(x=> {
                Console.Write(x.Key+"|"+x.Value+" ");
            });
            Console.WriteLine();

            Console.Write("LRUQues: ");
            while (_keyLruQue.Head != null)
            {
                Console.Write(_keyLruQue.Head.Value+" ");
                _keyLruQue.Pop();
            }

        }

    }
}
